package bu.met.cs664;

import java.awt.Point;
import java.util.ArrayList;
import java.util.List;

public class MoveEvaluator {

	private String[][] board;
	private Point wumpus;
	private boolean wumpusIsDead = false;

	private static String STENCH = "S", WUMPUS = "W", BREEZE = "B",
			PIT = "P";

	public MoveEvaluator(String[][] board) {
		this.board = board;
	}
	
	public MoveEvaluator(int boardSize) {
		this.board = new String[boardSize][boardSize];
	}

	/**
	 * Returns true if a room is safe, that is does not contain a pit nor a Wumpus
	 * @param row
	 * @param col
	 * @return whether a square is certainly safe
	 */
	public boolean isSafe(int row, int col) {
		return (notPit(row, col) && notWumpus(row, col));
	}
	
	/**
	 * Returns whether or not a room has been visited. If a precept has been recorded in that room
	 * it has been visited.
	 * @param row
	 * @param col
	 * @return if a room has been visited
	 */
	public boolean isVisited(int row, int col) {
		return board[row][col] !=null;
	}

	private void clearWumpus() {
		if (wumpus != null) {
			board[wumpus.x][wumpus.y] = null;
		}
	}
	private boolean notPit(int row, int col) {
		return !(roomContains(PIT, row, col) || surroundingRoomsAllContain(BREEZE,row,col));
	}
	
	/**
	 * Record that you have killed the wumpus
	 */
	public void deadWumpus() {
		wumpusIsDead = true;
		clearWumpus();
	}

	/**
	 * Returns true if there is definitely no wumpus there, either because of 
	 * observations nearby or because teh wumpus is dead.
	 * It returns false if there is a definitely a wumpus or there MAY be a sumpus because 
	 * we dont have enough information.
	 * @param row 
	 * @param col 
	 * @return definitely not a wumpus
	 */
	public boolean notWumpus(int row, int col) {
		if (wumpusIsDead) {
			return true;
		} else if (wumpus != null && definitelyAWumpus(row, col)) {
			return false; // ITS A WUMPUS!
		} else if (wumpus == null && surroundingRoomsAllContain(STENCH, row, col)) {
			// probably a wumpus
			return false;
		}
		return true;
	}

	/**
	 * Find whether a given symbol is contained within all explored rooms around the room given
	 * @param symbol
	 * @param row
	 * @param col
	 * @return
	 */
	private boolean surroundingRoomsAllContain(String symbol, int row, int col) {
		Point[] adjacent = getAdjacentRooms(row,col);
		for (Point room : adjacent) {
			if (!roomContainsOrUnexplored(symbol, room.x, room.y)) {
				return false;
			}
		}			
		return true;
	}
	
	/**
	 * Gets the list of rooms adjacent to the room position given
	 * @param row the row to search around
	 * @param col the column to search around
	 * @return an array of point
	 */
	private Point[] getAdjacentRooms(int row, int col) {
		List<Point> adjacent = new ArrayList<Point>();
		
		if (inBoard(row, col+1)) { adjacent.add(new Point(row, col+1));}
		if (inBoard(row+1, col)) { adjacent.add(new Point(row+1, col));}
		if (inBoard(row-1, col)) { adjacent.add(new Point(row-1, col));}
		if (inBoard(row, col-1)) { adjacent.add(new Point(row, col-1));}
		
		Point[] pointArray = new Point[adjacent.size()];
		return adjacent.toArray(pointArray);
	}
	
	private boolean roomContainsOrUnexplored(String symbol, int row, int col) {
		return inBoard(row,col) && (!isVisited(row,col) || (isVisited(row,col) && roomContains(symbol, row, col)));
	}

	private boolean roomContains(String symbol, int row, int col) {
		return inBoard(row, col) &&  board[row][col] != null && board[row][col].contains(symbol);
	}

	private boolean inBoard(int row, int col) {
		return row >= 0 && row < board.length && col >= 0 && col < board.length;
	}

	public boolean definitelyAWumpus(int row, int col) {
		return !wumpusIsDead && wumpus != null && wumpus.x == row && wumpus.y == col;
	}
	
	private void findWumpus() {
		for (int i=0; i < board.length; i++) {
			for (int j=0; j<board.length; j++) {
				Point[] adjacent = getAdjacentRooms(i,j);
				int stenchCount = 0;
				for (Point room : adjacent) {
					stenchCount += (roomContains(STENCH, room.x, room.y)? 1 : 0);
				}
				if (stenchCount > 1 && board[i][j] == null && wumpus == null) {
//					WUMPUS FOUND!!!!
					wumpus = new Point(i,j);
					updateSquare(i,j,WUMPUS);
				}
			}
		}
	}

	/**
	 * Record the precepts in a room given the coordinates and string of sensations
	 * @param row
	 * @param col
	 * @param sensations
	 */
	public void updateSquare(int row, int col, String sensations) {
		board[row][col] = sensations;
		//System.out.println("hey there " + sensations);
		//System.out.println("Wumpus dead?" + wumpusIsDead);
		//look for the wumpus every time a new sensation is found
		findWumpus();
	}

//TESTING CODE
	public static void main(String[] args) {
//		
		MoveEvaluator evaluator = new MoveEvaluator(5);
		
		
		evaluator.updateSquare(0, 1, BREEZE);
		evaluator.updateSquare(0, 3, BREEZE);
		evaluator.updateSquare(1, 2, BREEZE);
		//System.out.println("Should not be safe" + evaluator.isSafe(0,2));
		//System.out.println("Surrounding rooms should all contain Breeze " + evaluator.surroundingRoomsAllContain(BREEZE, 0, 2));
	}
//
//		String[][] masterBoard = { { "", "B", "P", "B", "" },
//				{ "", "", "B", "", "" },
//				{ "B", "", "S", "", "B" },
//				{ "B", "SB", "W", "G", "P" },
//				{ "B", "P", "BS", "", "B"}};
//		
//		evaluator.updateSquare(0, 0, "E");
//		
//		System.out.println("Safe " + evaluator.isSafe(0, 1));
//		
//		evaluator.updateSquare(0, 1, "B");
//		System.out.println("unex" + evaluator.roomContainsOrUnexplored(BREEZE, 0,1));
//		System.out.println("Safe 0,2" + evaluator.isSafe(0, 2));
//		System.out.println("Safe 1,1"+ evaluator.isSafe(1, 1));
//		System.out.println("Safe 0,0" + evaluator.isSafe(0,0));
//		
//		evaluator.updateSquare(1, 0, "");
//		System.out.println("Safe 1,1" + evaluator.isSafe(1,1));
//		
//		evaluator.updateSquare(1,1,"B");
//		
//		System.out.println("Safe 1,2" + evaluator.isSafe(1,2));
//		
//		MoveEvaluator evaluator2 = new MoveEvaluator(4);
//		
//		evaluator2.updateSquare(0, 0, "");
//		evaluator2.updateSquare(0, 1, STENCH);
//		System.out.println( evaluator2.definitelyAWumpus(1, 1));
//		System.out.println("not a wumpus " +  evaluator2.notWumpus(1, 1));
//		System.out.println("top row wumpus" + evaluator2.definitelyAWumpus(0, 2));
//		System.out.println("top row no wumpus should be false" + evaluator2.notWumpus(0, 2));
//		evaluator2.board[1][0] = STENCH;
//		
//		System.out.println( "shouldbe a wumpus" + evaluator2.definitelyAWumpus(1, 1));
//		evaluator2.findWumpus();
//		System.out.println("wumpus shouldnot  exist"+ evaluator2.wumpus.toString());
//		
//	}

}
